package cn.bitkit.component.id;

import cn.bitkit.base.exception.BusinessException;

/**
 * 雪花算法：简化版本，去除了数据中心id(dataId)，只保留了机器id(workId)。方便在单数据中心，容纳更多的实例
 * @author changbo
 */
public class SnowflakeId {

	public static final long START_EPOCH = 1500000000000L;
    public static final long WORKER_ID_BITS = 10L;
    public static final long SEQUENCE_BITS = 12L;
    public static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
    public static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + MAX_WORKER_ID;
    public static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

	private long workerId = 1;
    private long sequence = 1;
    private long lastTimestamp = -1L;

    public void init(long workerId){
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new BusinessException("workerId error");
        }
        this.workerId = workerId;
    }

    public synchronized Long getId() {
        long timestamp = System.currentTimeMillis();
        if (timestamp < lastTimestamp) {
            timestamp = lastTimestamp + 1;
            sequence = 0;
        }else if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = lastTimestamp + 1;
            }
        } else {
            sequence = 0;
        }

        lastTimestamp = timestamp;
        return ((timestamp - START_EPOCH) << TIMESTAMP_LEFT_SHIFT) |
                (workerId << SEQUENCE_BITS) |
                sequence;
    }

}
